﻿using ELab.ImageProcess;
using ELab.Message;
using System;
using System.Linq;
using System.Windows.Forms;
using ELab.Client;
using ELab.Communication;
using ELab.Communication.Messages;
using ELab.QuestionAnwer;
using System.Collections.Generic;
using ELab.Settings;
using System.Runtime.InteropServices;
using ELab.Serialization.Data;
using ELab.Hooking;
using System.Drawing;
using ELab.Student.Controls;
using ELab.View.TestExample;
using ELab.Management;
using ELab.Communication.Messages.ControllerMessages;
using WindowsInput;
using System.IO;
using ELab.Core;
using ELab.SystemWatcher;
using System.Threading.Tasks;
using ELab.Controls;

namespace ELab.Student
{

    public partial class frmStudentScreen : Form
    {
        // Public variable
        private HBlockInput hBlock = null;//new HBlockInput();
        private ELabClient _student;
        private List<ELabClient> _students = new List<ELabClient>();
        private System.Windows.Forms.Timer timer;
        private LessonTest examp = new LessonTest();
        private int timeRemaining = 0;
        private int index = 0;
        private System.Windows.Forms.Timer timerRemain = new System.Windows.Forms.Timer();
        private ClassMode viewMode = ClassMode.NONE;
        private User CurrentUser = null;
        private string UserRequestTeacher = "Teacher";
        private ElabWatcher watcher = new ElabWatcher();
        private string ipAddressServer = CommunicationConsts.DefaultIpAddress;
        private int portServer = CommunicationConsts.DefaultPort;
        ctrlDoTestSample sampleControl = new ctrlDoTestSample();
        ctrlTableMode sampleTableControl = new ctrlTableMode();
        public IEnumerable<User> Users { get; set; }
        public List<User> LoginUsers { get; set; }
        public frmStudentScreen()
        {
            InitializeComponent();
            sampleControl.RaiseComplete += frmStudentScreen_RaiseComplete;
            sampleControl.RaiseChangeIndex += sampleControl_RaiseChangeIndex;
            sampleControl.RaiseGetIndex += sampleControl_RaiseGetIndex;
            sampleTableControl.RaiseComplete += sampleTableControl_RaiseComplete;
            LoginUsers = new List<User>();
        }

        void sampleTableControl_RaiseComplete(object sender, EventArgs e)
        {
            //this.viewMode = ClassMode.NONE;
            //ThreadHelperClass.SetEnable(this, btnStartTest, false);
            ThreadHelperClass.SetText(this, lbStudentMessage, "You are completed the test example. Thank you!");
            //ThreadHelperClass.ClearControl(this, mainPanel, true);
        }

        void sampleControl_RaiseGetIndex(object sender, EventArgs e)
        {
            sampleControl.index = index;
        }

        void sampleControl_RaiseChangeIndex(object sender, EventArgs e)
        {
            index++;
        }


        void frmStudentScreen_RaiseComplete(object sender, EventArgs e)
        {
            this.viewMode = ClassMode.NONE;
            ThreadHelperClass.SetEnable(this, btnStartTest, false);
            ThreadHelperClass.SetText(this, lbStudentMessage, "You are completed the test example. Thank you!");
            ThreadHelperClass.ClearControl(this, mainPanel, true);
        }

        private void OnFormReSize(EventArgs e)
        {
        }
        public void CaptureAndsendScreen()
        {
            ScreenCapture scrCapture = new ScreenCapture();
            var img = scrCapture.CaptureScreen();//.Resize(50);
            //var imgArray = img.ToByteArray(ImageFormat.Jpeg);

            ScreenMessage msg = new ScreenMessage { Screem = img };

            //Message to tell sent all data
            EMessage sendSuccess = new EMessage { Screen = msg };
            var ms = _student.CreateMessage();
            ms.DestinationApplicationName = UserRequestTeacher;
            ms.MessageData = sendSuccess.Data;
            ms.TransmitRule = MessageTransmitRules.NonPersistent;
            ms.Send();
        }

        private int iTick = 0;
        private void timer_Tick(object sender, EventArgs e)
        {
            if (_student == null) return;
            //  send keyboard event to another application
            if ((_SenKeyBuff != null) && (_SenKeyBuff.Length > 0) && viewMode == ClassMode.REMOTE)
            {
                // Some keys need to be sent
                sendkey();
            }

            if (_Mouses.Count > 0 && viewMode == ClassMode.REMOTE)
                SendMouse();
            //----------------------
            iTick++;
            //dont check if not connected to server
            if (_student.CommunicationState != CommunicationStates.Connected) return;

            switch (viewMode)
            {
                // Nếu lớp học đang ở chế độ chữa bài - thì gửi màn hình của học sinh đến giáo viên;
                case ClassMode.VIEW_ONLY:
                    CaptureAndsendScreen();
                    break;

                case ClassMode.REMOTE:
                    CaptureAndsendScreen();
                    break;

                case ClassMode.TESTING:
                case ClassMode.TESTING_HANDUP:
                    if (iTick % 20 == 0)
                    {
                        if (timeRemaining <= 0)
                        {
                            iTick = 0;
                            sampleControl.SentResult();
                            MessageBox.Show("You are used full time to test. The result has been sent to Teacher");
                            return;
                        }

                        int min = (int)Math.Floor((double)timeRemaining / 60);
                        int second = timeRemaining - min * 60;
                        sampleControl.lbTimeRemaining.Text = string.Format("{0}:{1}", String.Format("{0:00}", min), String.Format("{0:00}", second));
                        timeRemaining--;
                        sampleControl.timeRemaining = this.timeRemaining;
                        sampleControl.index = this.index;
                        return;
                    }
                    break;

                case ClassMode.LOCKED:
                    switch (hBlock.BlockInputState)
                    {
                        case BlockInputState.NeedToBlock:
                            hBlock.StopBlock();
                            viewMode = ClassMode.NONE;
                            break;
                        case BlockInputState.Normal:
                            hBlock.StartBlock();
                            break;
                    }
                    break;

                default:
                    if (hBlock.BlockInputState == BlockInputState.Blocked)
                    {
                        hBlock.StopBlock();
                    }
                    break;
            }
        }

        #region KeyForSend
        private void frmStudentScreen_KeyDown(object sender, KeyEventArgs e)
        {
            if (viewMode != ClassMode.REMOTE)
            {
                e.Handled = true;
                return;
            }

            enterKey = new MessageKeyEventArgs(e.KeyData);
            enterKey.Alt = e.Alt;
            enterKey.Control = e.Control;
            enterKey.KeyCode = e.KeyCode;
            enterKey.KeyData = e.KeyData;
            enterKey.KeyValue = e.KeyValue;
            enterKey.Modifiers = e.Modifiers;
            enterKey.Shift = e.Shift;
            enterKey.UpDownStatus = 1;// down
            enterKey.SuppressKeyPress = e.SuppressKeyPress;



            SendKeyToRemote(enterKey);

            e.Handled = true;


        }

        private void frmStudentScreen_KeyUp(object sender, KeyEventArgs e)
        {
            if (viewMode != ClassMode.REMOTE)
            {
                e.Handled = true;
                return;
            }

            enterKey = new MessageKeyEventArgs(e.KeyData);
            enterKey.Alt = e.Alt;
            enterKey.Control = e.Control;
            enterKey.KeyCode = e.KeyCode;
            enterKey.KeyData = e.KeyData;
            enterKey.KeyValue = e.KeyValue;
            enterKey.Modifiers = e.Modifiers;
            enterKey.Shift = e.Shift;
            enterKey.UpDownStatus = 0;// down
            enterKey.SuppressKeyPress = e.SuppressKeyPress;


            // HaiNV2 if (viewMode==ClassMode.TESTING_HANDUP)
            SendKeyToRemote(enterKey);

            e.Handled = true;
        }
        private void SendKeyToRemote(MessageKeyEventArgs enterKey)
        {
            EMessage message = new EMessage { Event = new EventMessage { KeyEvent = enterKey } };
            var _TeacherAppName = Users.Where(x => x.Type == UserType.Teacher).Select(x => x.ApplicationName).FirstOrDefault();
            var ms = _student.CreateMessage();
            ms.DestinationApplicationName = _TeacherAppName;
            ms.TransmitRule = MessageTransmitRules.NonPersistent;
            ms.MessageData = message.Data;

            ms.Send();
        }
        private MessageKeyEventArgs enterKey = null;
        #endregion
        #region Mouse
        private void SendMouseToRemote(MessageMouseEventArgs mouse)
        {
            EMessage message = new EMessage { Event = new EventMessage { MouseEvent = mouse } };
            var _TeacherAppName = Users.Where(x => x.Type == UserType.Teacher).Select(x => x.ApplicationName).FirstOrDefault();

            var ms = _student.CreateMessage();
            ms.DestinationApplicationName = _TeacherAppName;
            ms.TransmitRule = MessageTransmitRules.NonPersistent;
            ms.MessageData = message.Data;

            ms.Send();
        }
        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out POINT lpPoint);
        public static Point GetCursorPosition()
        {
            POINT lpPoint;
            GetCursorPos(out lpPoint);
            //bool success = User32.GetCursorPos(out lpPoint);
            // if (!success)

            Point pRet = new Point();
            pRet.X = lpPoint.x;
            pRet.Y = lpPoint.y;

            return pRet;
        }
        private MessageMouseEventArgs GetMouseOverRemotingScreen2()
        {

            scvStudent.BorderStyle = BorderStyle.FixedSingle;

            Point curPos = GetCursorPosition();
            curPos = scvStudent.PointToClient(curPos);
            Point screenPos = scvStudent.PointToScreen(new Point((scvStudent.Left + scvStudent.Right) / 2, (scvStudent.Top + scvStudent.Bottom) / 2));

            // Re-caculate mouse position
            int dOrgCordinateX = (scvStudent.Left + scvStudent.Right) / 2;
            int dOrgCordinateY = (scvStudent.Top + scvStudent.Bottom) / 2;


            if ((curPos.X >= scvStudent.ClientRectangle.Left) && (curPos.X <= scvStudent.ClientRectangle.Right)
                && (curPos.Y >= scvStudent.ClientRectangle.Top) && (curPos.Y <= scvStudent.ClientRectangle.Bottom))
            {
                MouseButtons btn = new System.Windows.Forms.MouseButtons();
                int x = 0;
                int y = 0;
                MessageMouseEventArgs mouse = new MessageMouseEventArgs();

                mouse.X = curPos.X - dOrgCordinateX;
                mouse.Y = curPos.Y - dOrgCordinateY;
                mouse.ScreenWidth = scvStudent.Width;
                mouse.ScreenHeight = scvStudent.Height;
                mouse.ScreenX = curPos.X - screenPos.X;
                mouse.ScreenY = curPos.Y - screenPos.Y;

                return mouse;
            }
            return null;

        }
        private MessageMouseEventArgs GetMouseOverRemotingScreen()
        {

            Point curPos = GetCursorPosition();
            Point screenPos = scvStudent.PointToScreen(new Point(0, 0));
            MouseButtons btn = new System.Windows.Forms.MouseButtons();

            int Click = 0;
            int x = 0;
            int y = 0;
            MessageMouseEventArgs mouse = new MessageMouseEventArgs();
            //mouse.Location = new Point(curPos.X-screenPos.X, curPos.Y-screenPos.Y);
            mouse.X = curPos.X - screenPos.X;
            mouse.Y = curPos.Y - screenPos.Y;
            // Calulating the Shift cordinate

            Rectangle r = scvStudent.ClientRectangle;
            
            //if (_RemotingStudentScreenLst.ContainsKey(strStudentAppName))
            //{
            //    r = _RemotingStudentScreenLst[strStudentAppName];
            //    double sCale1 = (double)scvStudent.Width / r.Width;
            //    double sCale2 = (double)scvStudent.Height / r.Height;
            //    double sCaleFactor = Math.Min(sCale1, sCale2);
            //    double RealWith = r.Width * sCaleFactor;
            //    double ReadHeight = r.Height * sCaleFactor;
            //    int ShiftX = (int)(scvStudent.Width - RealWith) / 2;
            //    int ShiftY = (int)(scvStudent.Height - ReadHeight) / 2;
            //    mouse.X -= ShiftX;
            //    mouse.Y -= ShiftY;
            //    mouse.ScreenWidth = (int)RealWith;
            //    mouse.ScreenHeight = (int)ReadHeight;
            //}
            //else
            {
                mouse.ScreenWidth = r.Width;
                mouse.ScreenHeight = r.Height;
            }
            return mouse;

        }
        private void scvStudent_Click(object sender, EventArgs e)
        {


        }

        private void scvStudent_MouseHover(object sender, EventArgs e)
        {

        }

        private void scvStudent_MouseClick(object sender, MouseEventArgs e)
        {


        }

        private void scvStudent_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            //if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            //{
            //    MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
            //    mouse.Button = e.Button;
            //    mouse.Clicks = 2;
            //    SendMouseToRemote(_ViewUser.UserName, mouse);
            //}
        }
        private void scvStudent_MouseWheel(object sender, MouseEventArgs e)
        {
            //if (viewMode == ClassMode.TESTING_HANDUP)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen();
                if (mouse == null) return;
                mouse.Delta = e.Delta;
                mouse.Button = MouseButtons.None;
                SendMouseToRemote(mouse);

            }
        }
        private void scvStudent_MouseDown(object sender, MouseEventArgs e)
        {

            //if (viewMode == ClassMode.TESTING_HANDUP) // HaiNV2
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen();

                if (mouse == null) return;
                mouse.Button = e.Button;
                mouse.Clicks = e.Clicks;
                mouse.ButtonStatus = 1;// down
                SendMouseToRemote(mouse);

                _CurMouseStatus = 1;// Mouse down
                _CurMouseButton = e.Button;
            }
        }
        private void scvStudent_MouseUp(object sender, MouseEventArgs e)
        {

            //if (viewMode == ClassMode.TESTING_HANDUP)// HaiNv2
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen();
                if (mouse == null) return;
                mouse.Button = e.Button;
                mouse.Clicks = 1;// e.Clicks;
                mouse.ButtonStatus = 0;// up
                SendMouseToRemote(mouse);

                _CurMouseButton = MouseButtons.None;
                _CurMouseStatus = 0;// Mouse up
                _CurMouseButton = e.Button;
            }
        }

        private void scvStudent_DoubleClick(object sender, EventArgs e)
        {

        }


        byte _CurMouseStatus = 0;// mouse up
        MouseButtons _CurMouseButton = MouseButtons.None;
        private void mainPanel_MouseMove(object sender, MouseEventArgs e)
        {

            //if (viewMode == ClassMode.TESTING_HANDUP) // HaiNV2
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen();
                if (mouse == null) return;
                mouse.Clicks = 0;
                mouse.Button = MouseButtons.None;
                SendMouseToRemote(mouse);

            }
        }
        #endregion
        //--------------------------
        #region Hai Ngo Van
        private void frmStudentScreen_Load(object sender, EventArgs e)
        {
            ELabController controller = null;
            try
            {
                int attent = 0, maxattent = SystemConfiguration.ReconnectTimes;
                var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
                ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
                portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;

                while (attent < maxattent)
                {
                    try
                    {
                        controller = new ELabController(ipAddressServer, portServer);
                        controller.ReConnectServerOnError = true;
                        controller.Connect();
                        var message = controller.SendMessageAndGetResponse(new GetUsersMessage());
                        var userListMessage = message as GetUsersResponseMessage;
                        if (userListMessage != null && userListMessage.Users != null)
                        {
                            Users = userListMessage.Users;
                        }

                        // Need Login to do
                        frmLogin login = new frmLogin();
                        login.ShowDialog();
                        if (!login.IsSuccess)
                        {
                            MessageBox.Show("Cannot login for user: " + login.uLoginControl.CurrentUser);
                            Close();
                        }
                        CurrentUser = login.uLoginControl.CurrentUser;
                        this.LoginUsers.Add(CurrentUser);
                        lctStudents.Users = this.LoginUsers.ToArray();

                        //Begin load controls
                        ThreadHelperClass.SetEnable(this, btnStartTest, false);
                        lctStudents.UpdateButtonState(false);
                        ThreadHelperClass.SetText(this, lbStudentMessage, "You have no exercise to test.");

                        hBlock = new HBlockInput();
                        timer = new System.Windows.Forms.Timer();
                        timer.Interval = 50;
                        timer.Tick += timer_Tick;
                        timer.Enabled = true;

                        _student = new ELabClient(CurrentUser.UserName, ipAddressServer, portServer);
                        _student.ReConnectServerOnError = true;
                        _student.MessageReceived += _eLabClient_MessageReceived;
                        this.FormClosing += frmTeacherScreen_FormClosing;
                        _student.Connect();

                        InitKeyDict();
                        break;
                    }
                    catch (Exception es)
                    {
                        attent++;
                        if (attent >= maxattent) throw es;
                    }
                    finally
                    {
                        if (controller != null) controller.Disconnect();
                    }
                }
            }
            catch (Exception ex1)
            {
                MessageBox.Show(ex1.Message);
                this.Close();
            }
            finally
            {
                if (controller != null) controller.Disconnect();
            }
        }
        //-----------------------------
        #region DLL Imports
        [DllImport("User32.dll")]
        static extern int SetForegroundWindow(IntPtr point);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll")]
        static extern IntPtr GetActiveWindow();
        [DllImport("user32.dll")]
        static extern IntPtr GetFocus();
        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

        [DllImport("user32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo);

        [DllImport("User32.Dll")]
        public static extern long SetCursorPos(int x, int y);

        [DllImport("User32.Dll")]
        public static extern bool ClientToScreen(IntPtr hWnd, ref POINT point);

        #endregion
        //--------------------------------
        #region Global Declare
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;
        }



        private const int VK_RETURN = 0x0D;
        private const uint WM_KEYDOWN = 0x0100;
        private const uint WM_KEYUP = 0x0101;

        public const Int32 WM_CHAR = 0x0102;

        private const int WM_LBUTTONDOWN = 0x201; //Left mousebutton down
        private const int WM_LBUTTONUP = 0x202;   //Left mousebutton up

        private const uint WM_SYSKEYDOWN = 260;
        private const uint WM_SYSKEYUP = 261;
        //private const uint WM_CHAR =258;
        //private const uint WM_KEYUP = 257;
        const int KEYEVENTF_EXTENDEDKEY = 0x0001;
        //const int KEYEVENTF_KEYUP = 0x0002;
        const int KEYEVENTF_UNICODE = 0x0004;
        const int KEYEVENTF_SCANCODE = 0x0008;
        //------------------------------------

        [StructLayout(LayoutKind.Sequential)]
        struct KEYBDINPUT
        {
            public short wVk;      //Virtual KeyCode (not needed here)
            public short wScan;    //Directx Keycode 
            public int dwFlags;    //This tells you what is use (Keyup, Keydown..)
            public int time;
            public IntPtr dwExtraInfo;
        }
        [StructLayout(LayoutKind.Explicit)]
        struct INPUT
        {
            [FieldOffset(0)]
            public int type;
            [FieldOffset(4)]
            public KEYBDINPUT ki;
        }
        #endregion

        #region Public variable
        //-------------------------------------
        UserMessage uMgs;
        string _SenKeyBuff = "";
        List<int> _KeyValues = new List<int>();
        List<MessageKeyEventArgs> _Keys = new List<MessageKeyEventArgs>();
        List<MessageMouseEventArgs> _Mouses = new List<MessageMouseEventArgs>();
        //DateTime _LastStroke = DateTime.Now;
        Dictionary<string, string> _keyDict = new System.Collections.Generic.Dictionary<string, string>();
        #endregion
        //-------------------------------------


        public void Send_Key(short Keycode, int KeyUporDown)
        {
            INPUT[] InputData = new INPUT[1];

            InputData[0].type = 1;
            InputData[0].ki.wScan = Keycode;
            InputData[0].ki.dwFlags = KeyUporDown;
            InputData[0].ki.time = 0;
            InputData[0].ki.dwExtraInfo = IntPtr.Zero;

            SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
        }



        void InitKeyDict()
        {
            _keyDict.Add("BACKSPACE", "{BACKSPACE}");
            _keyDict.Add("BREAK", "{BREAK}");
            _keyDict.Add("CAPS LOCK", "{CAPSLOCK}");
            _keyDict.Add("DELETE", "{DELETE}");
            _keyDict.Add("DOWN ARROW", "{DOWN}");
            _keyDict.Add("END", "{END}");
            _keyDict.Add("ENTER", "{ENTER}");
            _keyDict.Add("ESC", "{ESC}");
            _keyDict.Add("HELP", "{HELP}");
            _keyDict.Add("HOME", "{HOME}");
            _keyDict.Add("INSERT", "{INSERT}");
            _keyDict.Add("LEFT ARROW", "{LEFT}");
            _keyDict.Add("NUM LOCK", "{NUMLOCK}");
            _keyDict.Add("PAGE DOWN", "{PGDN}");
            _keyDict.Add("PAGE UP", "{PGUP}");
            _keyDict.Add("PRINT SCREEN", "{PRTSC} (reserved for future use)");
            _keyDict.Add("RIGHT ARROW", "{RIGHT}");
            _keyDict.Add("SCROLL LOCK", "{SCROLLLOCK}");
            _keyDict.Add("TAB", "{TAB}");
            _keyDict.Add("UP ARROW", "{UP}");
            _keyDict.Add("F1", "{F1}");
            _keyDict.Add("F2", "{F2}");
            _keyDict.Add("F3", "{F3}");
            _keyDict.Add("F4", "{F4}");
            _keyDict.Add("F5", "{F5}");
            _keyDict.Add("F6", "{F6}");
            _keyDict.Add("F7", "{F7}");
            _keyDict.Add("F8", "{F8}");
            _keyDict.Add("F9", "{F9}");
            _keyDict.Add("F10", "{F10}");
            _keyDict.Add("F11", "{F11}");
            _keyDict.Add("F12", "{F12}");
            _keyDict.Add("F13", "{F13}");
            _keyDict.Add("F14", "{F14}");
            _keyDict.Add("F15", "{F15}");
            _keyDict.Add("F16", "{F16}");
            _keyDict.Add("Keypad add", "{ADD}");
            _keyDict.Add("Keypad subtract", "{SUBTRACT}");
            _keyDict.Add("Keypad multiply", "{MULTIPLY}");
            _keyDict.Add("Keypad divide", "{DIVIDE} ");
            _keyDict.Add("ShiftKey", "+");
            _keyDict.Add("Space", " ");
            _keyDict.Add("ontrolKey", "^");
        }


        void SendKey(ref List<MessageKeyEventArgs> _Keys)
        {
            for (int i = 0; i < _Keys.Count; i++)
            {

                if (_Keys[i].UpDownStatus == 1)// KeyDown
                {
                    if (_Keys[i].Control)
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.CONTROL);
                    if (_Keys[i].Shift)
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.SHIFT);
                    if (_Keys[i].KeyCode > 0)
                        InputSimulator.SimulateKeyDown((VirtualKeyCode)((ushort)_Keys[i].KeyValue));
                }
                else
                    if (_Keys[i].UpDownStatus == 0)// KeyUp
                    {
                        if (_Keys[i].Control)
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.CONTROL);
                        if (_Keys[i].Shift)
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.SHIFT);
                        if (_Keys[i].KeyCode > 0)
                            InputSimulator.SimulateKeyUp((VirtualKeyCode)((ushort)_Keys[i].KeyValue));
                    }
            }

            _Keys.Clear();
            _SenKeyBuff = "";
        }
        void sendkey()
        {
            SendKey(ref _Keys);

        }


        void SendMouse(ref List<MessageMouseEventArgs> _Mouses)
        {
            //get screen size
            Rectangle resolution = Screen.PrimaryScreen.Bounds;
            for (int i = 0; i < _Mouses.Count; i++)
            {

                double scale1 = (double)resolution.Width / (double)_Mouses[i].ScreenWidth;
                double scale2 = (double)resolution.Height / (double)_Mouses[i].ScreenHeight;
                double scaleFactor = Math.Min(scale1, scale2);
                int xShift = (int)(resolution.Width - _Mouses[i].ScreenWidth * scaleFactor) / 2;
                int yShift = (int)(resolution.Height - _Mouses[i].ScreenHeight * scaleFactor) / 2;

                MouseSimulator.MouseMove((int)(xShift + _Mouses[i].X * scaleFactor),
                   yShift + (int)(_Mouses[i].Y * scaleFactor));
                if (_Mouses[i].ButtonStatus == 1)// mouse down
                {

                    if (_Mouses[i].Clicks == 1)
                    {
                        if (_Mouses[i].Button == MouseButtons.Left)
                            MouseSimulator.LeftMouseDown();
                        //MouseSimulator.ClickLeftMouseButton();
                        else
                            if (_Mouses[i].Button == MouseButtons.Right)
                                MouseSimulator.RightMouseDown();
                                //MouseSimulator.ClickRightMouseButton();
                    }
                    else
                        if (_Mouses[i].Clicks == 2)// Double click
                        {

                            MouseSimulator.ClickLeftMouseButton();
                            MouseSimulator.ClickLeftMouseButton();
                        }
                }
                else
                    if (_Mouses[i].ButtonStatus == 0)// Mouse up
                    {
                        if (_Mouses[i].Clicks == 1)
                        {
                            if (_Mouses[i].Button != MouseButtons.None)
                            {


                                if (_Mouses[i].Button == MouseButtons.Left)
                                    MouseSimulator.LeftMouseUp();
                                else
                                    if (_Mouses[i].Button == MouseButtons.Right)
                                        MouseSimulator.RightMouseUp();
                            }

                        }
                    }

                if (_Mouses[i].Delta != 0)
                {
                    MouseSimulator.MouseWheel((uint)_Mouses[i].Delta);

                }
            }
            _Mouses.Clear();

        }
        void SendMouse()
        {
            SendMouse(ref _Mouses);

        }


        private void _eLabClient_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            e.Message.Acknowledge();
            EMessage retrieveMess = new EMessage(e.Message.MessageData);
            if (!retrieveMess.IsValidate) return;
            if (retrieveMess == null) return;

            if ((retrieveMess.Event != null) && (retrieveMess.Event.KeyEvent != null))
            {
                _SenKeyBuff += retrieveMess.Event.KeyEvent.KeyCode;
                _KeyValues.Add((int)retrieveMess.Event.KeyEvent.KeyData);
                _Keys.Add(retrieveMess.Event.KeyEvent);
            }
            else
            {
                if ((retrieveMess.Event != null) && (retrieveMess.Event.MouseEvent != null))
                {
                    _Mouses.Add(retrieveMess.Event.MouseEvent);
                }
                else
                {
                    if (retrieveMess.Command != null)
                    {
                        UserRequestTeacher = e.Message.SourceApplicationName;
                        switch (retrieveMess.Command.CommandType)
                        {
                            case CommandType.RequestCaptureScr:
                                viewMode = ClassMode.VIEW_ONLY;
                                break;

                            case CommandType.RequestRemote:
                                viewMode = ClassMode.REMOTE;
                                break;

                            case CommandType.RequestFinishCapture:
                                viewMode = ClassMode.NONE;
                                break;

                            case CommandType.RequestFinishRemote:
                                viewMode = ClassMode.NONE;
                                break;

                            case CommandType.RequestLockInput:
                                viewMode = ClassMode.LOCKED;
                                break;

                            case CommandType.RequestUnlockInput:
                                viewMode = ClassMode.NONE;
                                break;

                            case CommandType.RequestTestExample:
                                viewMode = ClassMode.TESTING;
                                examp = retrieveMess.Command.Body.Deserialize<LessonTest>();
                                timeRemaining = examp.TimeToTest;
                                index = 0;
                                ThreadHelperClass.SetEnable(this, btnStartTest, true);
                                lctStudents.UpdateButtonState(false);
                                ThreadHelperClass.SetText(this, lbStudentMessage, "You have received a new test example.");
                                break;

                            case CommandType.RequestTableExample:
                                viewMode = ClassMode.TABLE_TESTING;
                                examp = retrieveMess.Command.Body.Deserialize<LessonTest>();
                                timeRemaining = examp.TimeToTest;
                                index = 0;
                                ThreadHelperClass.SetEnable(this, btnStartTest, true);
                                lctStudents.UpdateButtonState(false);
                                ThreadHelperClass.SetText(this, lbStudentMessage, "You have received a new test example.");
                                break;

                            case CommandType.RequestTestExample_HandUp:
                                viewMode = ClassMode.TESTING_HANDUP;
                                examp = retrieveMess.Command.Body.Deserialize<LessonTest>();
                                timeRemaining = examp.TimeToTest;
                                index = 0;
                                ThreadHelperClass.SetEnable(this, btnStartTest, true);
                                lctStudents.UpdateButtonState(false);
                                ThreadHelperClass.SetText(this, lbStudentMessage, "You have received a new test example.");
                                break;

                            case CommandType.RequestRaiseHand:
                                if (viewMode == ClassMode.TESTING_HANDUP)
                                {
                                    uMgs = retrieveMess.Command.Body.Deserialize<UserMessage>();
                                    ThreadHelperClass.SetEnable(this, btnStartTest, false);
                                    lctStudents.UpdateButtonState(false);
                                    if (CurrentUser.UserName != uMgs.UserName)
                                        ThreadHelperClass.SetText(this, lbStudentMessage, "Another student working in the test.");
                                }
                                break;
                            case CommandType.RequestFreeHand:
                                if (viewMode == ClassMode.TESTING_HANDUP)
                                {
                                    uMgs = retrieveMess.Command.Body.Deserialize<UserMessage>();
                                    timeRemaining = uMgs.Time_Remaining;
                                    index = uMgs.Question_Index;
                                    if (CurrentUser.UserName != uMgs.UserName)
                                    {
                                        ThreadHelperClass.SetEnable(this, btnStartTest, true);
                                        ThreadHelperClass.SetText(this, lbStudentMessage, "You have received a new test example.");
                                    }
                                }
                                break;
                            case CommandType.RequestCompleteSample:
                                if (viewMode == ClassMode.TESTING_HANDUP)
                                {
                                    viewMode = ClassMode.NONE;
                                    uMgs = retrieveMess.Command.Body.Deserialize<UserMessage>();
                                    ThreadHelperClass.SetEnable(this, btnStartTest, false);
                                    ThreadHelperClass.SetText(this, lbStudentMessage, "You have no exercise to test.");
                                }
                                break;

                            case CommandType.RequestCheckFiles:
                                ProcessCheckFile(retrieveMess);
                                break;

                            case CommandType.RequestSendFiles:
                                ProcessReceiverFile(retrieveMess);
                                break;
                        }
                    }
                }
            }

            if (retrieveMess.Screen != null && retrieveMess.Screen.Screem != null)
            {
                var img = retrieveMess.Screen.Screem;
                if (!scvStudent.Visible)
                    ThreadHelperClass.SetEnable(this, scvStudent, true);
                scvStudent.Image = img;
            }
            else
            {
                if (scvStudent.Visible)
                    ThreadHelperClass.SetEnable(this, scvStudent, false);
                scvStudent.Image = null;
            }
        }

        private void ProcessCheckFile(EMessage retrieveMess)
        {
            FilesSynchMessage synMsg = FilesSynchMessage.FromData(retrieveMess.Command.Body);
            if (synMsg == null || synMsg.Users == null || synMsg.Users.Count == 0) return;

            var receiInfos = synMsg.FileInfors;
            var rootInfos = watcher.FileInfors;

            //files need to receiver
            var needInfos = receiInfos.Where(x => !rootInfos.Any(y => y.FileLength == x.FileLength && y.FileName.ToLower() == x.FileName.ToLower())).ToList();
            if (needInfos != null && needInfos.Count != 0)
            {
                FilesSynchMessage responseMsg = new FilesSynchMessage
                {
                    FileInfors = needInfos,
                    Users = new List<string> { CurrentUser.UserName }
                };
                EMessage message = new EMessage { Command = new CommandMessage { Body = responseMsg.Data, CommandType = CommandType.ResponseCheckFiles } };
                var ms = _student.CreateMessage();
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                ms.MessageData = message.Data;
                Parallel.ForEach(synMsg.Users, user =>
                {
                    ms.DestinationApplicationName = user;
                    ms.Send();
                });
            }

            //File need to send
            var sendInfos = rootInfos.Where(x => !receiInfos.Any(y => y.FileLength == x.FileLength && y.FileName.ToLower() == x.FileName.ToLower())).ToList();
            if (sendInfos != null && sendInfos.Count > 0)
            {
                Parallel.ForEach(sendInfos, sendInfo =>
                {
                    try
                    {
                        var FullPath = Path.Combine(SystemConfiguration.CurrentPath, SystemConfiguration.TransferFolder, sendInfo.FileName);
                        FileMessage fileMsg = new FileMessage { FilePath = FullPath, FileData = File.ReadAllBytes(FullPath) };
                        EMessage message = new EMessage { Command = new CommandMessage { Body = fileMsg.Data, CommandType = CommandType.RequestSendFiles } };
                        var ms = _student.CreateMessage();
                        ms.TransmitRule = MessageTransmitRules.NonPersistent;
                        ms.MessageData = message.Data;
                        Parallel.ForEach(synMsg.Users, user =>
                        {
                            ms.DestinationApplicationName = user;
                            ms.Send();
                        });
                    }
                    catch
                    {
                    }
                });
            }
        }

        private void ProcessReceiverFile(EMessage retrieveMess)
        {
            FileMessage synMsg = new FileMessage(retrieveMess.Command.Body);
            if (synMsg == null) return;
            var index = synMsg.FilePath.LastIndexOf('\\');
            var filename = (index > 0 ? synMsg.FilePath.Substring(index + 1) : synMsg.FilePath);
            var FullPath = Path.Combine(SystemConfiguration.CurrentPath, SystemConfiguration.TransferFolder, filename);
            File.WriteAllBytes(FullPath, synMsg.FileData);
        }

        private void frmTeacherScreen_FormClosing(object sender, FormClosingEventArgs e)
        {
            _student.Disconnect();
            _student.Dispose();

            foreach (var item in _students)
            {
                item.Disconnect();
                item.Dispose();
            }
        }
        #endregion
        private void btnStartTest_Click(object sender, EventArgs e)
        {
            ThreadHelperClass.SetEnable(this, btnStartTest, false);
            ThreadHelperClass.SetText(this, lbStudentMessage, "You are in testing mode.");
            if (viewMode == ClassMode.TABLE_TESTING)
            {
                sampleTableControl.examp = examp;
                sampleTableControl._student = _student;
                sampleTableControl.Users = this.Users;
                sampleTableControl.CurrentUser = this.CurrentUser;
                sampleTableControl.viewMode = viewMode;
                sampleTableControl.index = index;
                sampleTableControl.LoadQuestionForm();
                ThreadHelperClass.AddControl(this, mainPanel, sampleTableControl);
            }
            else
            {
                if (viewMode == ClassMode.TESTING_HANDUP) { RaiseHand(); }
                sampleControl.examp = examp;
                sampleControl._student = _student;
                sampleControl.Users = this.Users;
                sampleControl.CurrentUser = this.CurrentUser;
                sampleControl.viewMode = viewMode;
                sampleControl.index = index;
                sampleControl.LoadQuestionForm();
                ThreadHelperClass.AddControl(this, mainPanel, sampleControl);
            }
            lctStudents.UpdateButtonState(true);
        }
        private void RaiseHand()
        {
            var dataArr = new UserMessage() { UserName = CurrentUser.UserName }.SerializeToByteArray();
            CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestRaiseHand, Body = dataArr };
            EMessage mess = new EMessage { Command = comm };
            foreach (var user in this.Users.Where(u => u.UserName != CurrentUser.UserName))
            {
                var ms = _student.CreateMessage();
                ms.DestinationApplicationName = user.UserName;
                ms.MessageData = mess.Data;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                ms.Send();
            }
        }

        private void btnChangePass_Click(object sender, EventArgs e)
        {
            var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
            string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
            int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;
            var controller = new ELabController(ipAddressServer, portServer);

            ChangePassForm frm = new ChangePassForm();
            frm.Controller = controller;
            frm.CurrentUser = CurrentUser;
            frm.ShowDialog();
        }

        private void btnAddLogin_Click(object sender, EventArgs e)
        {
            var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
            string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
            int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;

            // Need Login to do
            frmLogin login = new frmLogin();
            login.ShowDialog();
            if (!login.IsSuccess)
            {
                MessageBox.Show("Cannot login for user: " + login.uLoginControl.CurrentUser);
                login.Close();
                return;
            }

            if (this.LoginUsers.Any(x => x.UserName == login.uLoginControl.CurrentUser.UserName))
            {
                MessageBox.Show("You are login befor with user: " + login.uLoginControl.CurrentUser);
                login.Close();
                return;
            }

            this.LoginUsers.Add(login.uLoginControl.CurrentUser);
            var _studentAdd = new ELabClient(login.uLoginControl.CurrentUser.UserName, ipAddressServer, portServer);
            _studentAdd.ReConnectServerOnError = true;
            _studentAdd.MessageReceived += _eLabClient_MessageReceived;
            _studentAdd.Connect();
            _students.Add(_studentAdd);
            lctStudents.Users = this.LoginUsers.ToArray();
        }

        private void lctStudents_OnItemAnswer(object sender, EventArgs e)
        {
            ThreadHelperClass.SetEnable(this, btnStartTest, false);
            ThreadHelperClass.SetText(this, lbStudentMessage, "You are in testing mode.");
            if (viewMode == ClassMode.TABLE_TESTING)
            {
                sampleTableControl.CurrentUser = ((StudentControl)sender).CurrentUser;
                sampleTableControl.FinishTesting();
            }
            else
            {
                if (viewMode == ClassMode.TESTING_HANDUP) { RaiseHand(); }
                sampleControl.CurrentUser = ((StudentControl)sender).CurrentUser;
                sampleControl.FinishTesting();
            }
        }

        private void lctStudents_OnItemLogout(object sender, EventArgs e)
        {
            var currentUser = ((StudentControl)sender).CurrentUser;
            this.LoginUsers.Remove(currentUser);

            if (this.LoginUsers == null || this.LoginUsers.Count == 0)
            {
                if (_student != null)
                {
                    _student.Disconnect();
                    _student.Dispose();
                }
                Application.Exit();
                return;
            }
            else
            {
                if (_student != null && currentUser.ApplicationName.ToUpper() == _student.ApplicationName.ToUpper())
                {
                    if (_student != null && this.LoginUsers != null && this.LoginUsers.Count > 0)
                    {
                        _student.Disconnect();
                        _student.Dispose();
                        _student = null;
                        CurrentUser = Users.FirstOrDefault(x => x.ApplicationName == this.LoginUsers[0].UserName);
                        _student = new ELabClient(CurrentUser.UserName, ipAddressServer, portServer);
                        _student.ReConnectServerOnError = true;
                        _student.MessageReceived += _eLabClient_MessageReceived;
                        _student.Connect();
                    }
                }
                else
                {
                    var removeApp = _students.FirstOrDefault(x => x.ApplicationName.ToUpper() == currentUser.ApplicationName.ToUpper());
                    if (removeApp != null)
                    {
                        removeApp.Disconnect();
                        removeApp.Dispose();
                        _students.Remove(removeApp);
                    }
                }
            }
            lctStudents.Users = this.LoginUsers.ToArray();
        }

        private void lctStudents_OnItemChangePass(object sender, EventArgs e)
        {
            var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
            string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
            int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;
            var controller = new ELabController(ipAddressServer, portServer);

            ChangePassForm frm = new ChangePassForm();
            frm.Controller = controller;
            var currentUser = ((StudentControl)sender).CurrentUser;
            frm.CurrentUser = currentUser;
            frm.ShowDialog();
        }
    }
}
